import {Component} from 'react';
import {Input} from 'antd';
import E from 'wangeditor';
import Toast from './Toast';
import {getLoginSession} from '../plugin/loginSession';
import {htmlDecode} from '../util/utils';
import styles from './css/WangEditor.css';
import {html_beautify} from 'js-beautify';

function formatFilterCodde(html, formatFun) {
	if (html) {
		let htmlBuf = '', 
			bufs,
			offset = 0;
		let reg = /<code>[\s\S]+?<\/code>/gm;
		while ((bufs = reg.exec(html)) != null) {
			let buf = bufs[0];
			htmlBuf += formatFun(html.substring(offset, reg.lastIndex - buf.length));
			offset = reg.lastIndex;
			htmlBuf += buf;
		}
		html = htmlBuf + formatFun(html.substring(offset));
	}
	return html;
}

function htmlFormatFilterCodde(html) {
	let htmlBuf = '', 
		bufs,
		offset = 0,
		bufs2 = [],
		i = 0;
	let reg = /<code>[\s\S]+?<\/code>/gm;
	while ((bufs = reg.exec(html)) != null) {
		let buf = bufs[0];
		htmlBuf += html.substring(offset, reg.lastIndex - buf.length);
		offset = reg.lastIndex;
		bufs2.push(buf);
		htmlBuf += '{{CODE_BUF' + (i ++) + '}}';
	}
	html = html_beautify(htmlBuf + html.substring(offset));
	let reg2 = new RegExp('<code>[\r\n\t]*{{CODE_BUF0}}[\r\n\t]*<\/code>', 'gm')
	if (bufs2 && bufs2.length > 0) {
		for (let n = 0; n < bufs2.length; n ++) {
			html = html.replace('{{CODE_BUF' + n + '}}', bufs2[n]);
		}
	}
	return html;
}

function getChildren(node) {
	let cs = node.children;
	if (!cs) 
		return node;
	else {
		let str = '';
		for (let c of cs) {
			str += getChildren(c);
		}
		return str;
	}
}

export default class WangEditor extends Component {
	
	constructor(...args) {
		super(...args);
		this.state = {
			html: ''
		}
		this.init = this.init.bind(this);
		this._focus = this._focus.bind(this);
		this._contenteditable = this._contenteditable.bind(this);
		this._renderMathJax = this._renderMathJax.bind(this);
		this._onCatalogChange = this._onCatalogChange.bind(this);
	}
	
	init({t, e}, defaultHtml) {
		let loginSession = getLoginSession() || {};
		let token = loginSession.token;
		t = t || this.refs.wangeditorToolbar;
		e = e || this.refs.wangeditorEditor;
		const editor = this._editor = new E(t, e);
		editor.customConfig = {
			zIndex: this.props.zIndex || 1,
			menus: this.props.menus || [
			    'head',// 标题
			    'bold',// 粗体
			    'italic',// 斜体
			    'underline',// 下划线
			    'strikeThrough',// 删除线
			    'foreColor',// 文字颜色
			    'backColor',// 背景颜色
			    'link',// 插入链接
			    'list',// 列表
			    'justify',// 对齐方式
			    'quote',// 引用
			    'emoticon',// 表情
			    'image',// 插入图片
			    'table',// 表格
			    'video',// 插入视频
			    'code',// 插入代码
			    'undo',// 撤销
			    'redo',// 重复
			],
			emotions: this.props.emotions || [],
			onchange: html => {
				this.setState({html: htmlFormatFilterCodde(html)})
				if(this.props.onChange && !this.props.readOnly) 
					this.props.onChange(html);
				this._onCatalogChange();
			},
			// 插入网络图片的回调
			linkImgCallback: url => {
				if(this.props.linkImgCallback) {
					this.props.linkImgCallback(url);
				}
			},
			// 插入链接的校验
			linkCheck: (text, link) => {
				if(this.props.linkCheck) {
					this.props.linkCheck(text, link);
				}
				return true;
			},
			linkImgCheck: src => {
				if(this.props.linkImgCheck) {
					return this.props.linkImgCheck(src);
				}
				return true;
			},
			uploadImgServer: this.props.uploadImgServer,
			uploadImgMaxSize: this.props.uploadImgMaxSize || 10 * 1024 * 1024,
			uploadImgMaxLength: this.props.uploadImgMaxLength || 5,
			uploadImgParams: this.props.uploadImgParams || {
				token: token && token.token,
				channel: token && token.channel
			},
			uploadImgParamsWithUrl: this.props.uploadImgParamsWithUrl || true,
			uploadFileName: this.props.uploadFileName,
			uploadImgHeaders: this.props.uploadImgHeaders || {},
			withCredentials: this.props.withCredentials || true,
			uploadImgTimeout: this.props.uploadImgTimeout || 600000,
			uploadImgHooks: this.props.uploadImgHooks || ({
				customInsert(insertImg, result, editor) {
					if (result.code == 1) {
						let imgs = result.data;
				        for(let img of imgs) {
				        	let url = img.thumbnailUrl || img.url;
				        	if(url)
				        		insertImg(url);
				        }
					} else
						Toast.show(result.msg)
			   },
			}),
			customAlert: this.props.customAlert || ((info) => {
				Toast.show(info)
			}),
		}
		editor.create();
		defaultHtml = defaultHtml || this.props.defaultHtml;
		if (defaultHtml) {
			editor.txt.html(defaultHtml || this.props.defaultHtml);
			this.setState({html: htmlFormatFilterCodde(defaultHtml)});
		}
		this._contenteditable();
		this._onCatalogChange();
		
	}
	
	_onCatalogChange() {
		if (this.props.onCatalogChange) {
			let tree = [];
			let offset = 0;
			let json = this._editor.txt.getJSON();
			
			let h1, h2, h3;
			for (let item of json) {
				
				let name = htmlDecode(getChildren(item));
				if (!name)
					continue
					
				if (item.tag == 'h1') {
					h1 = tree[tree.length] = {
						name,
						children: []
					}
					h2 = undefined;
				}
					
				if (item.tag == 'h2') {
					if (h1)
						h2 = h1.children[h1.children.length] = {
							name,
							children: []
						}
					else 
						h2 = tree[tree.length] = {
							name,
							children: []
						}
				}
				
				
				
			}
			this.props.onCatalogChange(tree)
		}
	}
	
	_focus() {
		this.refs.wangeditorEditor.querySelector('div').focus();
	}
	
	_contenteditable() {
		this._editor && this._editor.$textElem.attr('contenteditable', !(this.props.readOnly == true));
	}
	
	_renderMathJax() {
		if (this.props.readOnly) {
			global.MathJax && global.MathJax.Hub.Queue(["Typeset", MathJax.Hub, this.refs.showNode]);
		}
	}
	
	render() {
		let isHtml = this.props.isHtml && !this.props.readOnly || false;

		let editorClassName, htmlClassName;
		if (isHtml)
			editorClassName = styles.hidden;
		else 
			htmlClassName = styles.hidden;
		
		let showNode;
		if (this.props.readOnly) {
			editorClassName = styles.hidden;
			showNode = <div className='showNode findDom2' ref='showNode' dangerouslySetInnerHTML={{__html: this.props.html}} />
		}
		
		return(
			<div ref='wangeditorContainer'>
				<div className={'wangEditorContainer findDom1 ' + styles.editor + ' ' + editorClassName} onClick={this._focus}>
					<div ref='wangeditorToolbar'></div>
	        		<div ref='wangeditorEditor' style={{textAlign: 'left'}}></div>
	        	</div>
        		<div className={htmlClassName}>
        			<Input.TextArea value={this.state.html} autosize={true} onChange={e => {
        				
        				let html = e.target.value;
        				this.setState({html})
        				html = formatFilterCodde(html, htmlBuf => {
        					if (htmlBuf)
        						htmlBuf = htmlBuf.replace(/\n|\r|\t/g, '');
        					return htmlBuf;
        				});
        				
						if(this.props.onChange) 
							this.props.onChange(html);
        				this._editor.txt.html(html);
        				this._onCatalogChange();
        				let ta = this.refs.wangeditorContainer.querySelector('textarea');
        				ta.blur();
        				ta.focus();
        				
        			}} />
        		</div>
        		{showNode}
        	</div>
		);
	}
	
	componentDidMount() {
		if(this.props.customInit) {
			this.init();
			this._renderMathJax();
		}
	}
	
	componentDidUpdate () {
		this._contenteditable();
		this._renderMathJax();
	}
	
};